package dogo

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"

	"gitee.com/lflxp/dogo/plugin"

	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"sync"

	ctls "gitee.com/lflxp/dogo/tls"

	"gitee.com/lflxp/dogo/utils"
	"github.com/gin-gonic/gin"
	slog "github.com/go-eden/slf4go"
	"github.com/guonaihong/gout"
	cache "github.com/patrickmn/go-cache"
	"github.com/spf13/viper"
	"xorm.io/xorm"
)

var (
	GoOnRails *Rails
	once      sync.Once
)

type Rails struct {
	slog.Logger
	*gin.Engine
	HttpClient *gout.Client
	Http       *utils.GoutCli
	Orm        *xorm.Engine
	Cache      *cache.Cache
}

func NewRails() *Rails {
	once.Do(func() {
		GoOnRails = &Rails{}
		GoOnRails.Engine = plugin.NewGin()
		GoOnRails.Logger = plugin.NewLogger()
		GoOnRails.Orm = plugin.NewOrm()
		GoOnRails.HttpClient = plugin.GoutClient(true)
		GoOnRails.Cache = plugin.NewCacheCli()
		GoOnRails.Http = utils.NewGoutClient()
	})

	return GoOnRails
}

func Run(ishttps bool) {
	// gin.SetMode(gin.ReleaseMode)
	router := NewRails()

	ip := viper.GetString("host")
	port := viper.GetString("port")
	Infof("ip %s port %s", ip, port)

	if ip == "" || port == "" {
		// instance.Fatal("Check Host or Port config already!!!")
		ip = "0.0.0.0"
		port = "8000"
	}

	var server *http.Server
	if ishttps {
		err := ctls.Refresh()
		if err != nil {
			panic(err)
		}

		pool := x509.NewCertPool()
		caCeretPath := "ca.crt"

		caCrt, err := ioutil.ReadFile(caCeretPath)
		if err != nil {
			panic(err)
		}

		pool.AppendCertsFromPEM(caCrt)

		server = &http.Server{
			Addr:    fmt.Sprintf("%s:%s", ip, port),
			Handler: router,
			TLSConfig: &tls.Config{
				ClientCAs:  pool,
				ClientAuth: tls.RequestClientCert,
			},
		}
	} else {
		server = &http.Server{
			Addr:    fmt.Sprintf("%s:%s", ip, port),
			Handler: router,
		}

	}

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)

	go func() {
		<-quit
		Warn("receive interrupt signal")
		if err := server.Close(); err != nil {
			Fatal("Server Close:", err)
		}
	}()

	for _, ip := range GetIPs() {
		Infof("Listening and serving HTTPS on http://%s:%s", ip, port)
	}
	if ishttps {
		if err := server.ListenAndServeTLS("ca.crt", "ca.key"); err != nil {
			if err == http.ErrServerClosed {
				Warn("Server closed under request")
			} else {
				Fatalf("Server closed unexpect %s", err.Error())
			}
		}
	} else {
		if err := server.ListenAndServe(); err != nil {
			if err == http.ErrServerClosed {
				Warn("Server closed under request")
			} else {
				Fatalf("Server closed unexpect %s", err.Error())
			}
		}
	}

	Warn("Server exiting")
}
